/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package TablaDeSimbolos;

import java.util.ArrayList;
import java.util.Iterator;

/**
 *
 * @author Administrador
 */
public class TablaDeSimbolos {
    private ArrayList<ElementoDePila> pila;
    private int nivelLexico = -2;
    private static int ultimaEtiqueta= 1;

    public final int ENTERO = 0;
    public final int BOOLEAN = 1;
    public final int VARIABLE = 2;
    public final int CONSTANTE = 3;
    public final int TIPO = 4;



    public TablaDeSimbolos(){
        pila = new ArrayList<ElementoDePila>();
        apilarNivel();
        cargarPredefinidos();


    }

    public void cargarPredefinidos(){
        getTope().registrarConstante("TRUE", new Constante(1, new Booleano()));
        getTope().registrarConstante("FALSE", new Constante(0, new Booleano()));
        getTope().registrarConstante("MAXINT", new Constante(32767, new Entero()));
        getTope().registrarTipo("INTEGER", new Subrango(-32768, 32767));
        getTope().registrarTipo("BOOLEAN", new T_boolean());
        getTope().registrarProcedimiento("WRITE", new Procedimiento(1, new ArrayList<ParametroFormal>(), 0));
        getTope().registrarProcedimiento("WRITELN", new Procedimiento(1, new ArrayList<ParametroFormal>(), 0));
        getTope().registrarProcedimiento("READ", new Procedimiento(1, new ArrayList<ParametroFormal>(), 0));
        getTope().registrarProcedimiento("READLN", new Procedimiento(1, new ArrayList<ParametroFormal>(), 0));
    }

    public void apilarNivel(){
        nivelLexico++;
        ElementoDePila elemento = new ElementoDePila();
        pila.add(0,elemento);
         }

    public void apilarNivel(String ident){
        nivelLexico++;
        ElementoDePila elemento = new ElementoDePila(ident);
        pila.add(0,elemento);
         }

    public void apilarNivel(ElementoDePila nuevoTope){
        nivelLexico++;
        pila.add(0,nuevoTope);
         }

    public void desapilarNivel(){
        pila.remove(0);
        nivelLexico--;
    }

    public int getNivelLexico(){
        return nivelLexico;
    }

    public int nuevaEtiqueta(){
        int E = ultimaEtiqueta;
        ultimaEtiqueta++;
        return (E);
    }

    public boolean pertenece(String lexema){
        boolean pertenece = false;
        Iterator<ElementoDePila> it= pila.iterator();
        ElementoDePila nivel;
        lexema = lexema.toUpperCase();

        while (it.hasNext() && !pertenece){
            nivel = it.next();
            if (nivel.pertenece(lexema)){
                pertenece=true;
            }
        }
        return pertenece;
    }
    

    public boolean perteneceNivelActual(String lexema){
        ElementoDePila tope = getTope();

        return tope.pertenece(lexema);
    }

    public Elemento getEntrada(String lexema){
        boolean encontre = false;
        Iterator<ElementoDePila> it= pila.iterator();
        ElementoDePila nivel;
        Elemento elem = null;
        lexema = lexema.toUpperCase();
        while (it.hasNext() && !encontre){
            nivel = it.next();
            
            if (nivel.pertenece(lexema)){
                encontre=true;
                elem = nivel.getElemento(lexema);
            }
        }
        return elem;
    }

    public ElementoDePila getTope(){
       return pila.get(0);
    }

    public boolean compatibles(Tipo T1, Tipo T2){
        boolean compatible = false;

        if(T1.esBoolean()){
            compatible = T2.esBoolean();
        }
        else if(T2.esBoolean()){
            compatible = T1.esBoolean();
        }
        else if(T1.esEntero() || T1.esSubrango()){
            compatible = T2.esEntero() || T2.esSubrango();
        }
        else if(T1.esArreglo() && T2.esArreglo()){
            Arreglo ar1= (Arreglo) T1;
            Arreglo ar2= (Arreglo) T2;
            
            if ((ar1.getls()-ar1.getli())==(ar2.getls()-ar2.getli()) ){
                compatible= compatibles(ar1.getTipoIndice(), ar2.getTipoIndice()) && compatibles(ar1.getTipoElemento(),ar2.getTipoElemento());
            }
        }

        return compatible;
    }
}
